package com.lft.juc02.producterconsumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Function: 		A {@code PC} 线程之间的通信问题：生产者与消费者.<br/>
 * Reason:   		线程交替执行.<br/>
 * A B 操作现一个变量 num = 0
 * A num + 1
 * B num - 1
 * Date:            2021-01-29 15:51<br/>
 * <p>
 * Class Name:      PC<br/>
 * Package Name:    com.lft.juc02.producterconsumer<br/>
 * @author Laifengting / E-mail:laifengting@foxmail.com
 * @version 1.0.0
 * @since JDK 8
 */
public class PC_JUC {
	public static void main(String[] args) {
		Date2 date = new Date2();
		new Thread(()->{for(int i = 0; i < 10; i++)date.increment();},"~A~").start();
		new Thread(()->{for(int i = 0; i < 10; i++)date.decrement();},"~B~").start();
		new Thread(()->{for(int i = 0; i < 10; i++)date.increment();},"~C~").start();
		new Thread(()->{for(int i = 0; i < 10; i++)date.decrement();},"~D~").start();
	}
}

/**
 * 资源类——数据
 * 步骤：判断等待——业务——通知
 * /while(有资源){
 * /	等待
 * /}
 * /	业务
 * /	通知
 * /
 */
class Date2 {
	private int number = 0;
	private Lock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();
	
	// +1
	public void increment() {
		lock.lock();
		try {
			// 判断(不能用 if 判断，多线程时会出现虚假唤醒)
			while (number != 0) {
				// 等待
				try {
					condition.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			// 业务
			number++;
			System.out.println(Thread.currentThread().getName() + " 生产了第 " + number + " 个产品！");
			//通知其他线程，+1 完成。
			condition.signalAll();
		} finally {
			lock.unlock();
		}
		
	}
	
	// -1
	public void decrement() {
		lock.lock();
		try {
			// 判断(不能用 if 判断，多线程时会出现虚假唤醒)
			while (number == 0) {
				// 等待
				try {
					condition.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			// 业务
			number--;
			System.out.println(Thread.currentThread().getName() + " 消费了 " + number + " 号产品！");
			//通知其他线程，-1 完成。
			condition.signalAll();
		} finally {
			lock.unlock();
		}
	}
}
